#include <stdio.h>
#include <unistd.h>

#include "encrypt/chachapoly.h"
#include "LoRA.h"

#include "lora_task.h"
#include "mqtt_task.h"
#include "ota.h"
#include "ws_data.h"
#include "log.h"

#include <signal.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>

#include "libcli.h"

#define PWSAGENT_CLI_PORT 33333

unsigned int regular_count = 0;
unsigned int debug_regular = 0;

struct my_context {
  int value;
  char *message;
};

int regular_callback(struct cli_def *cli)
{
    regular_count++;
    if (debug_regular)
    {
        cli_print(cli, "Regular callback - %u times so far", regular_count);
        cli_reprompt(cli);
    }
    return CLI_OK;
}

int idle_timeout(struct cli_def *cli)
{
    cli_print(cli, "Custom idle timeout");
    return CLI_QUIT;
}

int cmd_test(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    int i;
    cli_print(cli, "called %s with \"%s\"", __func__, command);
    cli_print(cli, "%d arguments:", argc);
    for (i = 0; i < argc; i++)
        cli_print(cli, "        %s", argv[i]);

    return CLI_OK;
}

int cmd_ota(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    if (argv[0] == NULL) {
        cli_print(cli, "ota <filename>");
        return CLI_OK;
    }

    cli_print(cli, "ota load %s", argv[0]);
    loadOTAFile(cli, argv[0]);

    return CLI_OK;
}

int cmd_otastop(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    cli_print(cli, "Stop PWS ota.");
    OTAStop();
    return CLI_OK;
}

int cmd_otainfo(struct cli_def *cli, const char *command, char *argv[], int argc)
{
	cli_print(cli, "OTA status.");

	time_t			t;
	uint32_t		pos;
	uint16_t		per;
	struct tm		buf;
	char			str_t[30];

	GetOTAStatus(&t, &pos, &per);
	// // 时间 
	asctime_r(localtime_r(&t, &buf), str_t);

	cli_print(cli, "OTA send %d bytes, %d%%, @%s", pos, per, str_t);

	return CLI_OK;
}

int cmd_reboot(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    cli_print(cli, "Reboot PWS.");
    ws_reboot();
    return CLI_OK;
}

int cmd_boot2flash(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    cli_print(cli, "Boot to flash.");
    ws_boot2flash();
    return CLI_OK;
}

int cmd_otaconfirm(struct cli_def *cli, const char *command, char *argv[], int argc)
{
    cli_print(cli, "Update confirm.");
    ws_fwconfirm();
    return CLI_OK;
}

void run_child(int x)
{
    struct cli_command *c;
    struct cli_def *cli;
    struct cli_optarg *o;

    // Prepare a small user context
    // char mymessage[] = "I contain user data!";
    // struct my_context myctx;
    // myctx.value = 5;
    // myctx.message = mymessage;

    cli = cli_init();
    cli_set_banner(cli, "Chenhome PWS agent.");
    cli_set_hostname(cli, "PWS Agent");
    cli_telnet_protocol(cli, 1);
    cli_regular(cli, regular_callback);

    // change regular update to 5 seconds rather than default of 1 second
    cli_regular_interval(cli, 5);

    // set 60 second idle timeout
    cli_set_idle_timeout_callback(cli, 1800, idle_timeout);
    cli_register_command(cli, NULL, "test", cmd_test, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
    cli_register_command(cli, NULL, "ota", cmd_ota, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
    cli_register_command(cli, NULL, "reboot", cmd_reboot, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
    cli_register_command(cli, NULL, "boot2flash", cmd_boot2flash, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
    cli_register_command(cli, NULL, "otastop", cmd_otastop, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
	cli_register_command(cli, NULL, "otainfo", cmd_otainfo, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);
    cli_register_command(cli, NULL, "otaconfirm", cmd_otaconfirm, PRIVILEGE_UNPRIVILEGED, MODE_EXEC, NULL);

    cli_loop(cli, x);
    cli_done(cli);
}

int main(int argc, char* argv[]) {


    // 获取命令行的参数，判断是否需要debug，log，等其他信息（使用getopt即可）
    //  while ((c = getopt (argc, argv, "abc:")) != -1)

    logInit();

    InitOTA();

    mqttInit();

    ws_data_init();

    // LoRA task
    lora_task_init();

    int s, x;
    struct sockaddr_in addr;
    int on = 1;

    signal(SIGCHLD, SIG_IGN);

    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return 1;
    }

    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
    {
        perror("setsockopt");
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port = htons(PWSAGENT_CLI_PORT);
    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        return 1;
    }

    if (listen(s, 50) < 0)
    {
        perror("listen");
        return 1;
    }

    log_print(LOG_INFO, "Listening on port %d", PWSAGENT_CLI_PORT);
    while ((x = accept(s, NULL, 0)))
    {
        run_child(x);
    }

        return 0;
    }
